前面二篇談論如何建立與使用 semantic functions,接下來要談的就是Plugins的另一種function型態 - native functions,簡單來說native functions就是一般日常開發者悉熟用傳統程式語言所寫的的function,以Semantic Kernel來說目前支援 C#/Python/Java/TypeScript(coming soon)。
範例採用C#程式語言,並以主控台應用程式做為示範,使用的是.net 7.0。
此外GPT模型使用的是Azure OpenAI GPT-4,事實也可以依需求改用OpenAI服務,而模型也可以改用GPT-3.5。
native functions 以傳統程式語言所撰寫,像是讀寫檔案/發送API/時間日期運算/數學運算等,舉凡LLM模型自已無法做到的,都可以用native function來解決,也等同於增強LLM模型的能力,這取決於你的LLM應用場景。雖然native functions實際內容是傳統程式語言的程式碼,但是為了要讓Kernel載入Plugins後,可以知道這是一個function,因此必須使用 SKFunction decorator來定義這個function並且使用語義描述這個function的作用。結構上大致會是這個樣子的
public class MyPlugin
{
[SKFunction, Description("描述這個function的用途")]
public string NatvieFunSample()
{
return "SK Natvie Function Sample"; //do something
}
}
直接來操作演練試試,假設想建立一個可以取得客戶姓名的native function,那麼我們可以這麼做
public class Customer
{
public string GetCustomerContact(string cusCode)
{
//撰寫從CRM DataBase 取得客戶連絡人資料邏輯
//do something
return $"居匹踢";
}
}
public class Customer
{
[SKFunction, Description("取得客戶連絡人")]
public string GetCustomerContact(string cusCode)
{
//撰寫從CRM DataBase 取得客戶連絡人資料邏輯
//do something
return $"居匹踢";
}
}
// Import the Plugin .
var crmPlugin = kernel.ImportSkill(new Plugins.CrmPlugin.Customer(), "CrmPlugin");
// 經由Native Function取得指定客戶編號的連絡人姓名
var cusContactName = await kernel.RunAsync("C2023001", crmPlugin["GetCustomerContact"]);
上述的範例,不知道大家有沒有發現,結果看起來就是一個普通function,然後有回傳值這樣而已,那跟LLM應用的關係是?對的,沒錯,如果只是這樣做,其實完全沒有動用到LLM模型,那native function到底怎麼用?
讓我們再回想一下,實作LLM應用一切的源頭應來自於Prompt,對吧?那麼場景應該是轉變成LLM模型在處理Prompt時能夠意識到,在必要時刻時能夠調用native function。
那要怎麼改?直接來看
建立一個寫電子郵件的 semantic function (不知道什麼是semantic function請往前文章看)
skpromp.txt 給予以下內容
你是一位行政助理,負責處理我所交辧的文書作業任務
現在,請幫我寫一封信給
"""
{{$input}}
"""
內容是下星期1開始我將休假1個月,有任何緊急事項,可以連繫公司代理人
{
"schema": 1,
"type": "completion",
"description": "產生Email",
"completion": {
"max_tokens": 2000,
"temperature": 0.2,
"top_p": 0.0,
"presence_penalty": 0.0,
"frequency_penalty": 0.0
},
"input": {
"parameters": [
{
"name": "Input",
"description": "客戶姓名",
"defaultValue": ""
}
]
}
}
到這裡我們專案內具有2個Plugin,一個是native function,一個是semantic function
native function (CrmPlugin)負責從CRM系統取客戶姓名
semantic function(WriterPlugin) 負責寫email內容
調用function,工作流程上是先調用CrmPlugin拿到客戶姓名,再調用WriterPlugin寫email內容
// Import the Plugin .
var crmPlugin = kernel.ImportSkill(new Plugins.CrmPlugin.Customer(), "CrmPlugin");
// Import the Plugin from the plugins directory.
var pluginsDirectory = Path.Combine(System.IO.Directory.GetCurrentDirectory(), "Plugins");
var plugin = kernel.ImportSemanticSkillFromDirectory(pluginsDirectory, "WriterPlugin");
//調用CrmPlugin/GetCustomerContact function拿到客戶姓名
var getCusContact = kernel.Skills.GetFunction("CrmPlugin", "GetCustomerContact");
string cusContact = (await kernel.RunAsync("C2023001", getCusContact)).Result;
//調用WriterPlugin/Email function寫email內容
var writeEmail = kernel.Skills.GetFunction("WriterPlugin", "Email");
string email = (await kernel.RunAsync(cusContact, writeEmail)).Result;
Console.WriteLine(email);
範例原始碼 : https://github.com/iangithub/sklearn/tree/main/NativeFunctionSample
本篇內容說明如何實作natvie function,並且結合semantic function產生生成結果。然而,上述的做法並不夠好,不夠聰明,可以看到程式仍然以傳統思維的方式,按步就班手動調用Plugins,理想上應該一個prompt輸入後,自動調用Plugins,然後取得結果即可。下一篇我們將再進一步做調整。
嗨,我是Ian,我喜歡分享與討論,今年跟2位朋友合著了一本ChatGPT主題書,如果你是一位開發者,這本書或許會有些幫助,https://www.tenlong.com.tw/products/9786263335189
這次的鐵人賽文章也會同時發佈於個人blog,歡迎關注我的blog : https://medium.com/@ianchen_27500